package com.imooc.distributedemo.wallet;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.EthBlockNumber;
import org.web3j.protocol.http.HttpService;

import java.math.BigInteger;

// 12秒产生一个区块，可以间隔15个区块，去扫，因为刚刚产生的区块，会有问题
// 多线程处理ETH区块高度
// 12秒产生一个区块，可以间隔15个区块，多线程处理考虑[漏扫的区块]问题，
// 区块高度放到redis 里面  管理后台可以修改区块高度
// 区块高度作为参数去获取区块交易信息
// 日志输出 ： 最新区块高度 -  当前扫快区块高度
//  获取到区块高度，通过kafka 推送到业务层，然后解析区块信息，然后通过toaddress 判断是否是我们公司的地址，如果是就存到库里面
// 波卡，comos 这些链，需要nodejs 去写
@Slf4j
public class BlockHeightFetch {
    private final Web3j web3j;
    private final long pollInterval; // 轮询间隔时间，单位毫秒
    private final long targetBlocks; // 目标区块数量
    private BigInteger lastKnownBlockNumber; // 上次已知的区块高度

    public BlockHeightFetch(Web3j web3j, long pollInterval, long targetBlocks) throws Exception{
        this.web3j = web3j;
        this.pollInterval = pollInterval;
        this.targetBlocks = targetBlocks;
        this.lastKnownBlockNumber = web3j.ethBlockNumber().send().getBlockNumber();
    }

    public void start() {
        new Thread(this::poll).start();
    }

    private void poll() {
        while (true) {
            try {
                BigInteger latestBlockNumber = web3j.ethBlockNumber().sendAsync().get().getBlockNumber();//web3j.ethBlockNumber().send().getBlockNumber();
                log.info("=====最新区块高度和已获得区块高度差值:{},设定的区块高度间隙:{}=====",latestBlockNumber.subtract(lastKnownBlockNumber),targetBlocks);
                if (latestBlockNumber.subtract(lastKnownBlockNumber).compareTo(BigInteger.valueOf(targetBlocks)) >= 0) {
                    // 达到或超过目标区块高度，执行逻辑
                    log.error("区块高度获取异常,Reached target block height: {}",latestBlockNumber);
                    // TODO 这里应该是扫描出错了
                    // 跳出循环后后续处理？？
                    // ...

                    // 重置上次已知的区块高度
                    lastKnownBlockNumber = latestBlockNumber;
                }
                // 刚刚产生的区块会有问题， 解析上一次获取到的最新的区块
                if(latestBlockNumber.subtract(lastKnownBlockNumber).intValue()==1) {
                    // 处理对应逻辑 redis存lastKnownBlockNumber   通过kafka到业务系统
                    log.info("处理业务数据，解析区块信息:{}", lastKnownBlockNumber);
                    // redis.put   kafaka.sent
                    // 模拟处理解析区块具体数据
                    hanldeEthGetBlockByNumber(lastKnownBlockNumber);
                }

                lastKnownBlockNumber = latestBlockNumber;
                Thread.sleep(pollInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            } catch (Exception e) {
                log.error("轮询扫描获取区块高度异常了error",e);
            }

        }

    }

    private void hanldeEthGetBlockByNumber(BigInteger lastKnownBlockNumber) {
        try {
            DefaultBlockParameter parameter = new DefaultBlockParameterNumber(lastKnownBlockNumber);
            EthBlock ethBlock = web3j.ethGetBlockByNumber(parameter, true).sendAsync().get();
            String ethBlockJsonStr = JSON.toJSONString(ethBlock);
            log.info("解析的ethBlock数据是:{}",ethBlockJsonStr);
        }catch (Exception e){
            log.error("通过区块num解析区块数据异常,lastKnownBlockNumber:{}",lastKnownBlockNumber,e);
        }
    }

}
